function Map2D(width, height, gridWidth, gridHeight) {
	function SubGridMapping(object, subGrid) {
		this.object = object;
		this.subGrid = subGrid;
	};
	
	this.grid = [];
	this.width;
	this.height;
	this.gridWidth;
	this.gridHeight;
	
	this.objects = [];
	
	this.init = function(width, height, gridWidth, gridHeight) {
		this.width = width;
		this.height = height;
		this.gridWidth = gridWidth;
		this.gridHeight = gridHeight;

		for ( var i = 0; i < gridWidth; i++) {
			this.grid.push([]);
			for ( var j = 0; j < gridHeight; j++) {
				this.grid[i].push([]);
			}
		}
	};

	this.getGridPos = function(x, y) {
		var gridX = Math.floor((x * this.gridWidth) / this.width);
		var gridY = Math.floor((y * this.gridHeight) / this.height);
		return [gridX, gridY];
	};

	this.get = function(x, y, width, height) {
		if (width == null) {
			width = 0;
		}
		if (height == null) {
			height = 0;
		}
		var subGrid = [];
		var pos = this.getGridPos(x, y);
		var xMin = pos[0];
		var yMin = pos[1];

		pos = this.getGridPos(x + width, y + height);
		var xMax = pos[0];
		var yMax = pos[1];

		for ( var i = xMin; i <= xMax; i++) {
			for ( var j = yMin; j <= yMax; j++) {
				if (i >= 0 && i < this.gridWidth && j >= 0 && j < this.gridHeight)
					subGrid.push(this.grid[i][j]);
			}
		}
		return subGrid;
	};

	this.add = function(object, x, y, width, height) {
		var subGrid = this.get(x, y, width, height);
		for ( var i = 0; i < subGrid.length; i++) {
			subGrid[i].push(object);
		}
		this.objects[object.id] = new SubGridMapping(object, subGrid);
	};

	this.print = function() {
		console.log("map:\n");
		for ( var i = 0; i < this.gridHeight; i++) {
			line = "";
			for ( var j = 0; j < this.gridWidth; j++) {
				line += this.grid[j][i].length + "  ";
			}
			console.log(line);
		}
	};

	this.draw = function(ctx) {
		if (DEBUG_COLLISIONS) {
			ctx.strokeStyle = '#fa00ff';
			ctx.lineWidth = 1;
			var xStep = this.width / this.gridWidth;
			var yStep = this.height / this.gridHeight;
			for ( var i = 0; i < this.gridWidth; i++) {
				ctx.beginPath();
				ctx.moveTo(i * xStep, 0);
				ctx.lineTo(i * xStep, this.height);
				ctx.stroke();
				ctx.closePath();
			}
			for ( var i = 0; i < this.gridHeight; i++) {
				ctx.beginPath();
				ctx.moveTo(0, i * yStep);
				ctx.lineTo(this.width, i * yStep);
				ctx.stroke();
				ctx.closePath();
			}
		}

		for (var id in this.objects) {
			this.objects[id].object.draw(ctx);
		}

	};
	
	this.remove = function(object) {
		var subGrid = this.objects[object.id].subGrid; 
		for ( var i = 0; i < subGrid.length; i++) {
			var objects = subGrid[i];
			for ( var j = 0; j < objects.length; j++) {
				if (objects[j] === object) {
					objects[j] = objects[objects.length - 1];
					objects.pop();
				}
			}
		}

		delete this.objects[object.id];
	};
	
	this.init(width, height, gridWidth, gridHeight);
}